template<_Lock_policy _Lp>
class __shared_count
{
public:
    constexpr __shared_count() noexcept : _M_pi(0)
    { }

    template<typename _Ptr>
    explicit
    __shared_count(_Ptr __p) : _M_pi(0)
    {
        __try
        {
            _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
        }
        __catch(...)
        {
            delete __p;
            __throw_exception_again;
        }
    }

    template<typename _Ptr>
    __shared_count(_Ptr __p, /* is_array = */ false_type)
            : __shared_count(__p)
    { }

    template<typename _Ptr>
    __shared_count(_Ptr __p, /* is_array = */ true_type)
            : __shared_count(__p, __sp_array_delete{}, allocator<void>())
    { }

    template<typename _Ptr, typename _Deleter>
    __shared_count(_Ptr __p, _Deleter __d)
            : __shared_count(__p, std::move(__d), allocator<void>())
    { }

    template<typename _Ptr, typename _Deleter, typename _Alloc>
    __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
    {
        typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
        __try
        {
            typename _Sp_cd_type::__allocator_type __a2(__a);
            auto __guard = std::__allocate_guarded(__a2);
            _Sp_cd_type* __mem = __guard.get();
            ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
            _M_pi = __mem;
            __guard = nullptr;
        }
        __catch(...)
        {
            __d(__p); // Call _Deleter on __p.
            __throw_exception_again;
        }
    }

    template<typename _Tp, typename _Alloc, typename... _Args>
    __shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a,
                   _Args&&... __args)
            : _M_pi(0)
    {
        typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
        typename _Sp_cp_type::__allocator_type __a2(__a);
        auto __guard = std::__allocate_guarded(__a2);
        _Sp_cp_type* __mem = __guard.get();
        ::new (__mem) _Sp_cp_type(std::move(__a),
                                  std::forward<_Args>(__args)...);
        _M_pi = __mem;
        __guard = nullptr;
    }

#if _GLIBCXX_USE_DEPRECATED
    #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
     // Special case for auto_ptr<_Tp> to provide the strong guarantee.
     template<typename _Tp>
       explicit
 __shared_count(std::auto_ptr<_Tp>&& __r);
#pragma GCC diagnostic pop
#endif

    // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
    template<typename _Tp, typename _Del>
    explicit
    __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0)
    {
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2415. Inconsistency between unique_ptr and shared_ptr
        if (__r.get() == nullptr)
            return;

        using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
        using _Del2 = typename conditional<is_reference<_Del>::value,
                reference_wrapper<typename remove_reference<_Del>::type>,
        _Del>::type;
        using _Sp_cd_type
        = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
        using _Alloc = allocator<_Sp_cd_type>;
        using _Alloc_traits = allocator_traits<_Alloc>;
        _Alloc __a;
        _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1);
        _Alloc_traits::construct(__a, __mem, __r.release(),
                                 __r.get_deleter());  // non-throwing
        _M_pi = __mem;
    }

    // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
    explicit __shared_count(const __weak_count<_Lp>& __r);

    // Does not throw if __r._M_get_use_count() == 0, caller must check.
    explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t);

    ~__shared_count() noexcept
    {
        if (_M_pi != nullptr)
            _M_pi->_M_release();
    }

    __shared_count(const __shared_count& __r) noexcept
            : _M_pi(__r._M_pi)
    {
        if (_M_pi != 0)
            _M_pi->_M_add_ref_copy();
    }

    __shared_count&
    operator=(const __shared_count& __r) noexcept
    {
        _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
        if (__tmp != _M_pi)
        {
            if (__tmp != 0)
                __tmp->_M_add_ref_copy();
            if (_M_pi != 0)
                _M_pi->_M_release();
            _M_pi = __tmp;
        }
        return *this;
    }

    void
    _M_swap(__shared_count& __r) noexcept
    {
        _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
        __r._M_pi = _M_pi;
        _M_pi = __tmp;
    }

    long
    _M_get_use_count() const noexcept
    { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }

    bool
    _M_unique() const noexcept
    { return this->_M_get_use_count() == 1; }

    void*
    _M_get_deleter(const std::type_info& __ti) const noexcept
    { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; }

    bool
    _M_less(const __shared_count& __rhs) const noexcept
    { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

    bool
    _M_less(const __weak_count<_Lp>& __rhs) const noexcept
    { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }

    // Friend function injected into enclosing namespace and found by ADL
    friend inline bool
    operator==(const __shared_count& __a, const __shared_count& __b) noexcept
    { return __a._M_pi == __b._M_pi; }

private:
    friend class __weak_count<_Lp>;

    _Sp_counted_base<_Lp>*  _M_pi;
};

